package com.zhouyipeng;


import java.util.ArrayList;
import java.util.List;

/**
 * 投资/资产 预估
 *
 * @author zhouyipeng
 * @since 2021-08-14
 */
public class InvestmentEstimate0717 {

    public static void main(String[] args) {
        // 计划年数
        final int years = 10;
        // 年通货膨胀
        final double inflation = 0.07;
        // 每年本金
        List<Integer> amountList = new ArrayList<>(years);
        // 首年收入总额
        double salaryAmountFirst = 190000;
        // 每年收入涨幅
        double salaryUp = 0.06;
        // 预期每年投资收益率
        final double ratio = 0.1;
        // 当前每年所花费金额
        final double outMoneyMonth = 7000 * 12;

        // 计算每年工资
        List<Double> salaryListOfYears = calculateSalaryOfYears(years, salaryAmountFirst, salaryUp);
        System.out.println("计划每年工资 ： ");
        salaryListOfYears.forEach(one -> System.out.print(String.format("%.2f", one) + " / "));

        System.out.println("");
        System.out.println("计划每年月度工资 ： ");
        salaryListOfYears.forEach(one -> System.out.print(String.format("%.2f", one / 12) + " / "));

        System.out.println("");
        // 计算受通胀影响的结果    How many years ago？ = size - index
        List<Double> purchasingPower = calculateInflationAfterYears(salaryListOfYears, inflation);
        System.out.println("计划每年工资购买力 ： ");
        purchasingPower.forEach(one -> System.out.print(String.format("%.2f", one) + " / "));
        System.out.println("");

        // 计算受通胀影响，相同购买力所需金额
        List<Double> purchasingList = calculatePurchasing(years, outMoneyMonth, inflation);
        System.out.println("受通胀影响，相同购买力所需金额 ： ");
        purchasingList.forEach(one -> System.out.print(String.format("%.2f", one) + " / "));
        System.out.println("");

        // 计算每年可用于投资的钱
        List<Double> flexibleAmountList = calculateAmountByInvestment(years, salaryListOfYears, purchasingList);
        System.out.println("每年可用于投资的钱 ：");
        flexibleAmountList.forEach(one -> System.out.print(String.format("%.2f", one) + " / "));
        System.out.println("");

        // 计算复利长持诺干年后，每年投资最终本息和
        List<Double> principalAndInterestList = calculatePrincipalAndInterestList(years, flexibleAmountList, ratio);
        System.out.println("每年用于投资的钱，最终本息和 ：");
        principalAndInterestList.forEach(one -> System.out.print(String.format("%.2f",one)+ " / "));
        System.out.println("");
    }


    /**
     * 计划每年工资
     *
     * @param years             年数
     * @param salaryAmountFirst 首年工资
     * @param salaryUp          涨幅
     * @return
     */
    private static List<Double> calculateSalaryOfYears(int years, double salaryAmountFirst, double salaryUp) {

        List<Double> retList = new ArrayList<>(years);

        // 添加首年工资
        retList.add(salaryAmountFirst);

        // 计算每年应该达成的工资水平
        for (int i = 1; i < years; i++) {
            Double lastSalary = retList.get(i - 1);
            double temp = lastSalary * salaryUp + lastSalary;
            retList.add(temp);
        }
        return retList;
    }


    /**
     * 计算受通胀影响的最终购买力
     *
     * @param paramsList 每年金额
     * @param inflation  通胀率
     * @return
     */
    private static List<Double> calculateInflationAfterYears(List<Double> paramsList, double inflation) {

        // 购买力折扣
        double inflationResult = 1 - inflation;

        // 结果集
        List<Double> retList = new ArrayList<>(paramsList.size());

        for (int i = 0; i < paramsList.size(); i++) {
            // 当年工资
            double salary = paramsList.get(i);
            // 经过几年
            int years = paramsList.size() - i;

            // 此年购买力折扣
            double thisInflationResult = inflationResult;
            for (int j = 1; j < years; j++) {
                thisInflationResult = thisInflationResult * inflationResult;
            }
            double purchasingPower = salary * thisInflationResult;
            retList.add(purchasingPower);
        }
        return retList;
    }

    /**
     * 计算受通胀影响，相同购买力所需金额
     *
     * @param years         年数
     * @param outMoneyMonth 当前每月花费
     * @param inflation     年通胀率
     * @return
     */
    private static List<Double> calculatePurchasing(int years, double outMoneyMonth, double inflation) {
        // 结果集
        List<Double> retList = new ArrayList<>(years);

        double inflationResult = 1 + inflation;

        for (int i = 0; i < years; i++) {

            // 次年通胀结果
            double thisInflationResult = inflationResult;
            // 累计通胀结果
            for (int j = 1; j <= i; j++) {
                thisInflationResult = thisInflationResult * inflationResult;
            }
            double purchasingPower = outMoneyMonth * thisInflationResult;
            retList.add(purchasingPower);
        }
        retList.remove(retList.size() - 1);
        retList.add(0, outMoneyMonth);
        return retList;
    }


    /**
     * 计算每年可用于投资的钱
     *
     * @param years             年数
     * @param salaryListOfYears 每年工资
     * @param purchasingList    每年所需购买力
     * @return
     */
    private static List<Double> calculateAmountByInvestment(int years, List<Double> salaryListOfYears, List<Double> purchasingList) {

        List<Double> retList = new ArrayList<>();
        if (null == salaryListOfYears || null == purchasingList) {
            return retList;
        }

        years = years <= salaryListOfYears.size() ? years : salaryListOfYears.size();
        years = years <= purchasingList.size() ? years : purchasingList.size();

        // 计算每年可用于投资的钱
        List<Double> amountList = new ArrayList<>(years);
        for (int i = 0; i < years; i++) {
            Double tempA = salaryListOfYears.get(i);
            Double tempB = purchasingList.get(i);
            double temp = tempA - tempB;
            if (temp < 0) {
                temp = 0;
            }
            amountList.add(temp);
        }

        return amountList;
    }


    /**
     * 计算复利长持诺干年后，每年投资最终本息和
     *
     * @param years
     * @param flexibleAmountList
     * @param ratio
     * @return
     */
    private static List<Double> calculatePrincipalAndInterestList(int years, List<Double> flexibleAmountList, double ratio) {
        // 次年收益率
        double tempRatio = 1 + ratio;
        // 结果集
        List<Double> retList = new ArrayList<>(years);

        for (int i = years- 1; i >= 0; i--) {
            Double tempAmount = flexibleAmountList.get(i);

            retList.add(0,tempRatio * tempAmount);
            tempRatio = tempRatio * (1 + ratio);
        }


        return retList;
    }
}
